package cn.iocoder.yudao.module.scenic.service.trip;

import cn.hutool.core.bean.BeanUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.scenic.controller.admin.checkin.vo.CheckInPageByLocationResVO;
import cn.iocoder.yudao.module.scenic.controller.admin.trip.vo.*;
import cn.iocoder.yudao.module.scenic.controller.app.road.vo.RoadTripRespVO;
import cn.iocoder.yudao.module.scenic.controller.app.road.vo.RoadTripVO;
import cn.iocoder.yudao.module.scenic.dal.dataobject.spot.SpotDO;
import cn.iocoder.yudao.module.scenic.dal.dataobject.trip.TripDO;
import cn.iocoder.yudao.module.scenic.dal.mysql.spot.SpotMapper;
import cn.iocoder.yudao.module.scenic.dal.mysql.trip.TripMapper;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jodd.util.StringUtil;
import org.apache.logging.log4j.util.Strings;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.scenic.enums.ErrorCodeConstants.TRIP_NOT_EXISTS;

/**
 * 线路 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class TripServiceImpl implements TripService {

    @Resource
    private TripMapper tripMapper;

    @Resource
    DeptApi deptApi;

    @Resource
    SpotMapper spotMapper;

    @Override
    public Long createTrip(TripSaveReqVO createReqVO) {
        // 插入
        TripDO trip = BeanUtils.toBean(createReqVO, TripDO.class);
        List<Long> spotIdList = createReqVO.getSpotIdList();
        String join = Strings.join(spotIdList, ',');
        trip.setLine(join);
        trip.setLineName(transformName(spotIdList));
        tripMapper.insert(trip);
        // 返回
        return trip.getId();
    }

    private String transformName(List<Long> spotIdList) {
        Set set = new HashSet(spotIdList);
        QueryWrapper<SpotDO> spotDOQueryWrapper = new QueryWrapper();
        spotDOQueryWrapper.in("id", new ArrayList<>(set));
        List<SpotDO> spotDOS = spotMapper.selectList(spotDOQueryWrapper);
        Map<Long, SpotDO> deptRespDTOMap = spotDOS.stream().collect(Collectors.toMap(SpotDO::getId, Function.identity()));
        Map<Long, SpotDO> finalDeptRespDTOMap = deptRespDTOMap;
        StringBuilder stringBuilder = new StringBuilder();
        for (Long id : spotIdList) {
            if (finalDeptRespDTOMap.containsKey(id)) {
                SpotDO spotDO = finalDeptRespDTOMap.get(id);
                stringBuilder.append(spotDO.getName()).append("-->");
            }
        }
        if (stringBuilder.length() > 3) {
            return stringBuilder.substring(0, stringBuilder.length() - 3);
        }
        return stringBuilder.toString();
    }

    @Override
    public void updateTrip(TripSaveReqVO updateReqVO) {
        // 校验存在
        validateTripExists(updateReqVO.getId());
        // 更新
        TripDO updateObj = BeanUtils.toBean(updateReqVO, TripDO.class);
        List<Long> spotIdList = updateReqVO.getSpotIdList();
        String join = Strings.join(spotIdList, ',');
        updateObj.setLine(join);
        updateObj.setLineName(transformName(spotIdList));
        tripMapper.updateById(updateObj);
    }

    @Override
    public void deleteTrip(Long id) {
        // 校验存在
        validateTripExists(id);
        // 删除
        tripMapper.deleteById(id);
    }

    private void validateTripExists(Long id) {
        if (tripMapper.selectById(id) == null) {
            throw exception(TRIP_NOT_EXISTS);
        }
    }

    @Override
    public TripRespVO getTrip(Long id) {
        TripRespVO tripRespVO = new TripRespVO();
        TripDO tripDO = tripMapper.selectById(id);
        BeanUtil.copyProperties(tripDO, tripRespVO);
        String line = tripDO.getLine();
        String[] split = line.split(",");
        String lineName = tripDO.getLineName();
        String[] splitName = lineName.split("-->");
        List<Long> idList = Arrays.stream(split).map(Long::parseLong).collect(Collectors.toList());
        tripRespVO.setLineList(idList);
        tripRespVO.setLineNameList(Arrays.asList(splitName));
        return tripRespVO;
    }

    @Override
    public PageResult<TripDO> getTripPage(TripPageReqVO pageReqVO) {
        return tripMapper.selectPage(pageReqVO);
    }

    @Override
    public List<RoadTripRespVO> findByDeptId(Long id) {
        QueryWrapper<TripDO> wrapper = new QueryWrapper();
        wrapper.eq("dept_id", id);
        List<TripDO> list = tripMapper.selectList(wrapper);
        Map<Long, List<TripDO>> collect = list.stream().collect(Collectors.groupingBy(TripDO::getId));
        if (!collect.isEmpty()) {
            return collect.entrySet().stream().map(entry -> {
                RoadTripRespVO roadTripRespVO = new RoadTripRespVO();
                List<TripDO> value = entry.getValue();
                for (TripDO roadTripVO : value) {
                    roadTripRespVO.setRoadId(roadTripVO.getId());
                    roadTripRespVO.setRoadName(roadTripVO.getName());
                    roadTripRespVO.setPicAddress(roadTripVO.getPicAddress());
                    String line = roadTripVO.getLine();
                    if (!StringUtil.isBlank(line)) {
                        List<RoadTripRespVO.ScenicSpotRespVO> scenicSpotRespVOS = new ArrayList<>();
                        String[] split = line.split(",");
                        List<Long> sortSpiltList = Arrays.stream(split).map(Long::parseLong).sorted().collect(Collectors.toList());
                        QueryWrapper<SpotDO> spotDOQueryWrapper = new QueryWrapper();
                        spotDOQueryWrapper.in("id", sortSpiltList);
                        List<SpotDO> spotDOS = spotMapper.selectList(spotDOQueryWrapper);
                        for (SpotDO spotDO : spotDOS) {
                            RoadTripRespVO.ScenicSpotRespVO vo = new RoadTripRespVO.ScenicSpotRespVO();
                            vo.setLat(spotDO.getLat());
                            vo.setLnt(spotDO.getLnt());
                            vo.setSpotId(spotDO.getId());
                            vo.setSpotName(spotDO.getName());
                            scenicSpotRespVOS.add(vo);
                        }
                        roadTripRespVO.setScenicSpots(scenicSpotRespVOS);
                    }
                }
                return roadTripRespVO;
            }).collect(Collectors.toList());
        }
        return Collections.emptyList();

    }

    @Override
    public PageResult<TripPageByLocationResVO> tripPageByLocation(TripPageByLocationReqVO pageReqVO) {
        IPage<TripPageByLocationResVO> allPage = new Page(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        IPage<TripPageByLocationResVO> tripList = tripMapper.selectTripListByCondition(allPage, pageReqVO);
        PageResult<TripPageByLocationResVO> page = new PageResult<>();
        List<TripPageByLocationResVO> records = tripList.getRecords();
        if (!CollectionUtils.isEmpty(records)) {
            List<Long> collect = records.stream().map(TripPageByLocationResVO::getDeptId).collect(Collectors.toList());
            CommonResult<List<DeptRespDTO>> result = deptApi.getDeptList(collect);
            Map<Long, DeptRespDTO> deptRespDTOMap = new HashMap<>();
            if (result.isSuccess()) {
                List<DeptRespDTO> deptRespDTOList = result.getData();
                if (!CollectionUtils.isEmpty(deptRespDTOList)) {
                    deptRespDTOMap = deptRespDTOList.stream().collect(Collectors.toMap(DeptRespDTO::getId, Function.identity()));
                }
            }
            Map<Long, DeptRespDTO> finalDeptRespDTOMap = deptRespDTOMap;
            List<TripPageByLocationResVO> list = records.stream().map(s -> {
                List<Long> idList = new ArrayList<>();
                String line = s.getLine();
                if (StringUtil.isNotBlank(line)) {
                    String[] split = line.split(",");
                    for (String s1 : split) {
                        idList.add(Long.parseLong(s1));
                    }
                }
                s.setLineList(idList);
                s.setLineName(s.getLineName());
                if (finalDeptRespDTOMap.containsKey(s.getDeptId())) {
                    s.setDeptName(finalDeptRespDTOMap.get(s.getDeptId()).getName());
                }
                return s;
            }).collect(Collectors.toList());
            page.setList(list);
        }
        page.setTotal(tripList.getTotal());
        return page;
    }

}